package com.keter.dtx.service.tcc.impl;

import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.keter.dtx.service.tcc.ResultHolder;
import com.keter.dtx.service.tcc.TccActionOne;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * The type Tcc action one.
 *
 * @author zhangsen
 */
@Component
public class TccActionOneImpl implements TccActionOne {
    private static final Logger logger = LoggerFactory.getLogger(TccActionOneImpl.class);

    @Override
    public boolean prepare(BusinessActionContext context, int id, String name) {
        // Seata 框架本身仅提供两阶段原子提交协议，保证分布式事务原子性。事务的隔离需要交给业务逻辑来实现。
        // TCC 模型的隔离性思想就是通过业务的改造，在第一阶段结束之后，从底层数据库资源层面的加锁过渡为上层业务层面的加锁，
        // 从而释放底层数据库锁资源，放宽分布式事务锁协议
        logger.info("TccAction1 PREPARE, xid:{}, actionName:{}, id:{}, name:{}",
                context.getXid(),
                context.getActionName(),
                context.getActionContext("id"),
                context.getActionContext("name"));
        // 保存记录原始内容用于回滚
        Record r = Db.findFirst("select id, name from action_one where id=?", id);
        if(r==null) {
            logger.error("请确保action_one表中包含ID=1的数据！");
            return false;
        }
        ResultHolder.setResult(context, r);
        logger.info("TccAction1 Data for RollBack: id={}, name={}",
                ResultHolder.getResult(context).get("id"),
                ResultHolder.getResult(context).get("name"));
        return true;
    }

    /**
     * 模拟数据库更新操作
     * @param context the action context
     * @return
     */
    @Override
    public boolean commit(BusinessActionContext context) {
        // 从上下文中获取传递的业务参数
        int id = (int) context.getActionContext("id");
        String name = (String) context.getActionContext("name");
        logger.info("TccAction1 to COMMIT - xid:{}, id:{}, name:{}", context.getXid(), id, name);
        //修改 action_one 记录
        Db.update("update action_one set name=? where id=?", name, id);
        return true;
    }

    @Override
    public boolean rollback(BusinessActionContext context) {
        Record r = ResultHolder.getResult(context);
        if(r==null){
            logger.info("TccAction One 事务尚未提交！");
            return true;
        }
        int id = (int) context.getActionContext("id");
        String name = r.get("name");
        logger.info("TccActionOne ROLLBACK - xid:{}, id:{}, name:{}", context.getXid(), id, name);
        //使用修改前的记录值还原记录内容
        Db.update("update action_one set name=? where id=?", name, id);
        return true;
    }
}
